﻿#include "ImageCode.h"

#include <QByteArray>
#include <QImage>
#include <QBuffer>
#include <QPixmap>
#include <QByteArray>
#include <QDebug>
#include <SMTData.h>
#include <SMTGUI.h>
#include "SciData.h"
#include <SciVision.h>
#include "opencv2\opencv.hpp"

using namespace cv;


//将SmtImage图片格式转成Base64
QByteArray SmtImagetoBase64(SMTImage* pImage, int CompressionRatio)
{
	QImage* image = new QImage();
	SMTImageToQImage(pImage, *image);
	QByteArray ba;
	QBuffer buf(&ba);
	image->save(&buf, "JPG", CompressionRatio);
	QByteArray hexed = ba.toBase64();
	buf.close();
	delete image;
	return hexed;
}

QByteArray SmtImagetoBase64(SMTImage* pImage, SMTImage& packImage,int imageQuality)
{
    QImage* image = new QImage();
    SMTImageToQImage(pImage, *image);
    QByteArray ba;
    QBuffer buf(&ba);
	buf.open(QIODevice::ReadWrite);
    image->save(&buf, "JPG", imageQuality);

	//把压缩图转到SMTImage
	/*QPixmap imageresult;
	imageresult.loadFromData(ba);
	QImage tempImage = imageresult.toImage();*/
	QImage::Format format =  image->format();
	uchar* transData = reinterpret_cast<uchar*>(ba.data());
	QImage tempImage(transData,image->width(),image->height(),format);
	tempImage.loadFromData(ba);
	
	QImageToSmtImage(tempImage, &packImage);
	
    QByteArray hexed = ba.toBase64();
    buf.close();
	delete image;
    return hexed;
}

QByteArray SmtImagetoBase64(SMTImage* pImage, QImage& packImage, int imageQuality)
{
	QImage* image = new QImage();
	SMTImageToQImage(pImage, *image);
	QByteArray ba;
	QBuffer buf(&ba);
	buf.open(QIODevice::ReadWrite);
	image->save(&buf, "JPG", imageQuality);

	//把压缩图转到SMTImage
	QPixmap imageresult;
	imageresult.loadFromData(ba);
	packImage = imageresult.toImage();

	QByteArray hexed = ba.toBase64();
	buf.close();
	delete image;
	return hexed;
}

SMTImage Base64toSmtImage(QByteArray* hexed)
{

	QByteArray Ret_bytearray;
	Ret_bytearray = QByteArray::fromBase64(*hexed);
	QBuffer buffer(&Ret_bytearray);
	buffer.open(QIODevice::WriteOnly);
	QPixmap imageresult;
	imageresult.loadFromData(Ret_bytearray);
	QImage tempImage = imageresult.toImage();
	SMTImage pImage;
	QImageToSmtImage(tempImage, &pImage);
	return pImage;
}


bool QImageToSmtImage(const QImage& qImage, SMTImage* pImage)
{
	int w = 0, h = 0;
	unsigned char* r = NULL, *g = NULL, *b = NULL;

	w = qImage.width();
	h = qImage.height();

	bool bl = false;
	int type = qImage.format();
	switch (type)
	{
		case QImage::Format_Indexed8:
		{
			g = new unsigned char[w * h];
			for (int i = 0; i < h; i++)
			{
				const unsigned char* scanline = qImage.scanLine(i);
				memcpy(&g[w * i], scanline, w);
			}
			int iperline = qImage.bytesPerLine();
			bl = pImage->GenImageExt(g, iperline, h, w, 1, SMTImage::DATA_8U);
			delete[] g;
			break;
		}
		case QImage::Format_RGB888:
		{
			int iperline = qImage.bytesPerLine();
			int ihei = qImage.height();
			int iwid = qImage.width();
			int type = SMTImage::DATA_8U;
			int ich = 3;
			const unsigned char* scanline = qImage.constBits();
			bl = pImage->GenImageExt((void*)scanline, iperline, ihei, iwid, ich, (SMTImage::DataType)type);
			SciImage* sciImage = nullptr;
			sciImage->pData = pImage->data;
			SCIVISION::SciColorSpace toolColorSpace;
			toolColorSpace.CvtColorSpace(*sciImage, sciImage, SciCvtColor::SCI_BGR_TO_RGB);
			pImage->data = sciImage->pData;
			break;
		}
		case QImage::Format_RGB32:
		{
			//QImage rgbImage = qImage.convertToFormat(QImage::Format_RGB888);
			int iperline = qImage.bytesPerLine();
			int ihei = qImage.height();
			int iwid = qImage.width();
		
			
			const unsigned char* scanline = qImage.bits();

			cv::Mat mat = cv::Mat(ihei,iwid,CV_8UC4,const_cast<uchar*>(scanline),qImage.bytesPerLine());
			cv::Mat mat2 = cv::Mat(mat.rows,mat.cols,CV_8UC3);
			int from_to[] = { 0,0,1,1,2,2 };
			cv::mixChannels(&mat, 1, &mat2, 1, from_to, 3);

			int ich = mat2.channels();
			bl = pImage->GenImageExt(mat2.data, mat2.step, mat2.rows, mat2.cols, ich, SMTImage::DATA_8U);
			break;
		}
		case QImage::Format_Grayscale8:
		{
			int iperline = qImage.bytesPerLine();
			int ihei = qImage.height();
			int iwid = qImage.width();
			const unsigned char* scanline = qImage.bits();
			int ich = 1;
			bl = pImage->GenImageExt((void *)scanline, iperline, ihei, iwid, ich, SMTImage::DATA_8U);
			break;
		}
		default:
		{

		}
	}
	return bl;
}

bool SMTImageToQImage(SMTImage* smtImage, QImage& image)
{
	long long  width = 0, height = 0;
	unsigned char* r = NULL, *g = NULL, *b = NULL;
	long long channels = 0, number;

	channels = smtImage->channel();
	if (channels < 1)
	{
		return false;
	}

	width = smtImage->width();
	height = smtImage->height();
	int iDepth = smtImage->depth();

	switch (channels)
	{
	case 1:
	{
		g = (unsigned char*)smtImage->dataPtr();

		if (iDepth != 0)
		{
			return false;
		}

		image = QImage(width, height, QImage::Format_Indexed8);
		for (int i = 0; i < height; i++)
		{
			unsigned char* scanline = image.scanLine(i);
			memcpy(scanline, &g[width * i], width);
		}
		image.setColorCount(256);
		for (int index = 0; index < 256; index++)
			image.setColor(index, qRgb(index, index, index));
		return true;
	}
	case 3:
	{
		std::vector<Mat> MultiImages;
		Mat *pMat = (Mat*)((SciImage*)smtImage->data)->pData;
		if (pMat->empty())
		{
			QString outputMsg = "image data is corrupt data";
			qCritical() << outputMsg;
		}

		cv::split(*pMat, MultiImages);

		r = (unsigned char*)MultiImages[2].data;
		g = (unsigned char *)MultiImages[1].data;
		b = (unsigned char *)MultiImages[0].data;

		if (iDepth != 0)
			return true;

		image = QImage(width, height, QImage::Format_RGB32);
		for (int i = 0; i < height; i++)
		{
			unsigned char* scanline = image.scanLine(i);
			for (int j = 0; j < width; j++)
			{
				scanline[j * 4 + 2] = r[width*i + j];
				scanline[j * 4 + 1] = g[width*i + j];
				scanline[j * 4 + 0] = b[width*i + j];
			}
		}

		/*SMTImage::DataType dataType =  smtImage->dataType();
		unsigned char* imagePtr = smtImage->dataPtr();
		image = QImage(imagePtr,smtImage->width(),smtImage->height(),smtImage->step(),QImage::Format_RGB888);*/

		return true;
		break;
	}
	case 4:
	{
		g = (unsigned char*)smtImage->dataPtr();
		if (iDepth != 0)
			return false;

		image = QImage(width, height, QImage::Format_RGB32);
		for (int i = 0; i < height; i++)
		{
			unsigned char* scanline = image.scanLine(i);
			for (int j = 0; j < width; j++)
			{
				scanline[j * 4 + 0] = g[width * i + j];
				j++;
				scanline[j * 4 + 1] = g[width * i + j];
				j++;
				scanline[j * 4 + 2] = g[width * i + j];

			}
		}
		return true;
		break;
	}

	default:
		break;
	}
	return true;
}

static inline bool is_base64(unsigned char c) {
	return (isalnum(c) || (c == '+') || (c == '/'));
}

std::string base64_decode(std::string const& encoded_string) {
	int in_len = encoded_string.size();
	int i = 0;
	int j = 0;
	int in_ = 0;
	unsigned char char_array_4[4], char_array_3[3];
	std::string ret;

	while (in_len-- && (encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
		char_array_4[i++] = encoded_string[in_]; in_++;
		if (i == 4) {
			for (i = 0; i < 4; i++)
				char_array_4[i] = base64_chars.find(char_array_4[i]);

			char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
			char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
			char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
			for (i = 0; (i < 3); i++)
				ret += char_array_3[i];
			i = 0;
		}
	}

	if (i)
	{
		for (j = i; j < 4; j++)
			char_array_4[j] = 0;
		for (j = 0; j < 4; j++)
			char_array_4[j] = base64_chars.find(char_array_4[j]);
		char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
		char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
		char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
		for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
	}
	return ret;
}

int base64toImgResize(std::string base64, SMTImage* baseImg, int height, int widght)
{
	std::string decoded_string = base64_decode(base64);
	vector<uchar> data(decoded_string.begin(), decoded_string.end());
	if (data.size() != 0)
	{
		Mat img = imdecode(data, IMREAD_UNCHANGED);
		Mat srcimg;

		cv::Size size;
		size.height = height;
		size.width = widght;
		resize(img, srcimg, size, 0, 0, CV_INTER_NN);

		baseImg->GenImageExt((unsigned char*)srcimg.datastart, srcimg.step, srcimg.rows, srcimg.cols, srcimg.channels(), SMTImage::DATA_8U);
	}

	return 0;
}
